package org.arch_learn.rpc.nz_rpc.configuration;

import org.apache.curator.framework.CuratorFramework;
import org.arch_learn.rpc.nz_rpc.annos.RpcReference;
import org.arch_learn.rpc.nz_rpc.endpoint.NettyRpcClient;
import org.arch_learn.rpc.nz_rpc.proxy.NettyRpcClientProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Configuration
@ConditionalOnBean(name = "nettyRpcClients")
@AutoConfigureAfter(RPCAutoConfiguration.class)
public class RPCConsumerAutoConfiguration {
    @Autowired
    private ConcurrentHashMap<String, List<NettyRpcClient>> nettyRpcClients;
    @Autowired
    private CuratorFramework curatorFramework;

    //对所有引入被@Reference标注的属性生成代理实例，注入到引入类中。
    @Bean
    public BeanPostProcessor beanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessBeforeInitialization(Object bean, String beanName)
                    throws BeansException {
                Class<?> objClz;
                if (AopUtils.isAopProxy(bean)) {
                    objClz = AopUtils.getTargetClass(bean);
                } else {
                    objClz = bean.getClass();
                }
                try {
                    for (Field field : objClz.getDeclaredFields()) {
                        RpcReference reference = field.getAnnotation(RpcReference.class);
                        if (reference != null) {
                            Class<?> fieldType = field.getType();
                            NettyRpcClientProxy nettyRpcClientProxy = new NettyRpcClientProxy(nettyRpcClients, curatorFramework);
                            Object proxyObject = nettyRpcClientProxy.createProxy(fieldType);
                            field.setAccessible(true);
                            try {
                                field.set(bean, proxyObject);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                                System.out.println("实例属性：" + field.getName() + "注入失败！");
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return bean;
            }

            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName)
                    throws BeansException {
                return bean;
            }
        };
    }
}
